package com.zhss.dfs.backupnode.server;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 负责管理内存中的文件目录树的核心组件
 *
 * @author zhonghuashishan
 */
public class FSDirectory {

    /**
     * 内存中的文件目录树
     */
    private INodeDirectory dirTree;
    /**
     * 文件目录树的读写锁
     */
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    //当前文件目录树更新到了哪个txid;
    private volatile long maxTxid = 0;

    private void writeLock() {
        lock.writeLock().lock();
    }

    private void writeUnlock() {
        lock.writeLock().unlock();
    }

    private void readLock() {
        lock.readLock().lock();
    }

    private void readUnlock() {
        lock.readLock().unlock();
    }

    public FSDirectory() {
        this.dirTree = new INodeDirectory("/");
    }

    //以json方式获取文件目录树数据
    public FSImage getFSImage() {
        try {
            this.readLock();
            String json = JSON.toJSONString(dirTree);
            FSImage fsImage = new FSImage();
            fsImage.setFsimageJson(json);
            fsImage.setMaxTxid(maxTxid);
            return fsImage;
            //在这个时刻，我们还需要知道，当前这份元数据，同步到的最大的txid是多少
            //这样我们才知道，这个fsimage是对应这txid等于多少的editlog，在这个txid之前的editlog都可以删除了
        } finally {
            this.readUnlock();
        }
    }

    /**
     * 创建目录
     *
     * @param path 目录路径
     */
    public void mkdir(Long txid, String path) {
        // path = /usr/warehouse/hive
        // 你应该先判断一下，“/”根目录下有没有一个“usr”目录的存在
        // 如果说有的话，那么再判断一下，“/usr”目录下，有没有一个“/warehouse”目录的存在
        // 如果说没有，那么就得先创建一个“/warehosue”对应的目录，挂在“/usr”目录下
        // 接着再对“/hive”这个目录创建一个节点挂载上去
        try {
            this.writeLock();
            maxTxid = txid;
            String[] pathes = path.split("/");
            INodeDirectory parent = dirTree;

            for (String splitedPath : pathes) {
                if (splitedPath.trim().equals("")) {
                    continue;
                }

                INodeDirectory dir = findDirectory(parent, splitedPath);
                if (dir != null) {
                    parent = dir;
                    continue;
                }

                INodeDirectory child = new INodeDirectory(splitedPath);
                parent.addChild(child);
                parent = child;
            }
        } finally {
            this.writeUnlock();
        }
    }

    /**
     * 查找子目录
     *
     * @param dir
     * @param path
     * @return
     */
    private INodeDirectory findDirectory(INodeDirectory dir, String path) {
        if (dir.getChildren().size() == 0) {
            return null;
        }

        INodeDirectory resultDir;

        for (INode child : dir.getChildren()) {
            if (child instanceof INodeDirectory) {
                INodeDirectory childDir = (INodeDirectory) child;

                if ((childDir.getPath().equals(path))) {
                    return childDir;
                }

//                resultDir = findDirectory(childDir, path);
//                if (resultDir != null) {
//                    return resultDir;
//                }
            }
        }

        return null;
    }


    /**
     * 代表的是文件目录树中的一个节点
     *
     * @author zhonghuashishan
     */
    private interface INode {

    }

    /**
     * 代表文件目录树中的一个目录
     *
     * @author zhonghuashishan
     */
    public static class INodeDirectory implements INode {

        private String path;
        private List<INode> children;

        public INodeDirectory(String path) {
            this.path = path;
            this.children = new LinkedList<INode>();
        }

        public void addChild(INode inode) {
            this.children.add(inode);
        }

        public String getPath() {
            return path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public List<INode> getChildren() {
            return children;
        }

        public void setChildren(List<INode> children) {
            this.children = children;
        }

        @Override
        public String toString() {
            return "INodeDirectory{" +
                    "path='" + path + '\'' +
                    ", children=" + children +
                    '}';
        }
    }

    /**
     * 代表文件目录树中的一个文件
     *
     * @author zhonghuashishan
     */
    public static class INodeFile implements INode {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "INodeFile{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    @Override
    public String toString() {
        return "FSDirectory{" +
                "dirTree=" + dirTree +
                '}';
    }


    public void printDirTree(INodeDirectory dir, int live) {
        if (dir.getChildren() == null || dir.getChildren().size() <= 0) {
            return;
        }
        for (INode child : dir.getChildren()) {
            for (int i = 0; i < live; i++) {
                System.out.print("  ");
            }
            System.out.println("/" + ((INodeDirectory) child).getPath());
            printDirTree((INodeDirectory) child, live + 1);
        }
    }
}
